package mechanism;

import db.Chess;
import db.Player;
import result.Result;
import util.Client;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;

/**
 * @author 化尘成影
 * @Description 五子棋游戏逻辑核心
 * @date 2022/6/27 13:29
 */
public class GoBangBoard extends JPanel implements MouseListener {
    //创建玩家对象
    public Player owner;//玩家自己
    public Player rival;//对手

    public static String name;

    public final int MARGIN = 30;//边距
    public final int GRID_SPAN = 35;//网格间距
    public final int ROWS = 15;//棋盘行数
    public final int COLS = 15;//棋盘列数

    Chess[] chessList = new Chess[(ROWS + 1) * (COLS + 1)];
    public String[][] board;//棋盘
    public String chessBoard = "-";
    public boolean isYour = false;//记录当前是否轮到你来下
    public boolean isStart = true;//记录游戏是否开始
    public boolean gameOver = false;
    public boolean isPlayWithAi = false;
    public boolean isOut = false;//玩家是否退出房间
    public int chessCount;//记录当前棋子数量
    private int xIndex, yIndex;
    private int count = 0;

    Color colorTemp;

    public int i = 1;

    public GoBangBoard() {
        addMouseListener(this);
        addMouseMotionListener(new MouseMotionListener() {
            @Override
            public void mouseDragged(MouseEvent e) {

            }

            @Override
            public void mouseMoved(MouseEvent e) {
                //下棋的坐标
                int x1 = (e.getX() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;
                int y1 = (e.getY() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;

                if (count == 0) {
                    newBoard();
                }
                count++;

                boolean full = true;
                if (x1 <= 15 && y1 <= 15) {
                    full = isFull(x1, y1);
                }

                if (x1 < 0 || x1 > ROWS || y1 < 0 || y1 > COLS || gameOver || full) {
                    setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                } else {
                    setCursor(new Cursor(Cursor.HAND_CURSOR));
                }
            }
        });
    }

    //绘制棋盘
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        //画棋盘
        for (int i = 0; i <= ROWS; i++) {//画横线
            g.drawLine(MARGIN, MARGIN + i * GRID_SPAN, MARGIN + COLS * GRID_SPAN, MARGIN + i * GRID_SPAN);
        }
        for (int i = 0; i <= COLS; i++) {//画竖线
            g.drawLine(MARGIN + i * GRID_SPAN, MARGIN, MARGIN + i * GRID_SPAN, MARGIN + ROWS * GRID_SPAN);
        }

        //画棋子
        for (int i = 0; i < chessCount; i++) {
            //网格交叉点x，y坐标
            int xPos = chessList[i].getX() * GRID_SPAN + MARGIN;
            int yPos = chessList[i].getY() * GRID_SPAN + MARGIN;
            g.setColor(chessList[i].getColor());//设置颜色

            colorTemp = chessList[i].getColor();
            if (colorTemp == Color.black) {
                RadialGradientPaint paint = new RadialGradientPaint(xPos - Chess.DIAMETER / 2 + 25, yPos - Chess.DIAMETER / 2 + 10, 20, new float[]{0f, 1f}
                        , new Color[]{Color.WHITE, Color.BLACK});
                ((Graphics2D) g).setPaint(paint);
                ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);

            } else if (colorTemp == Color.white) {
                RadialGradientPaint paint = new RadialGradientPaint(xPos - Chess.DIAMETER / 2 + 25, yPos - Chess.DIAMETER / 2 + 10, 70, new float[]{0f, 1f}
                        , new Color[]{Color.WHITE, Color.BLACK});
                ((Graphics2D) g).setPaint(paint);
                ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);

            }

            Ellipse2D e = new Ellipse2D.Float(xPos - Chess.DIAMETER / 2, yPos - Chess.DIAMETER / 2, 34, 35);
            ((Graphics2D) g).fill(e);
            //标记最后一个棋子的红矩形框

            if (i == chessCount - 1) {//如果是最后一个棋子
                g.setColor(Color.red);
                g.drawRect(xPos - Chess.DIAMETER / 2, yPos - Chess.DIAMETER / 2,
                        34, 35);
            }
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
        if (rival == null) {
            JOptionPane.showMessageDialog(this, "请等待玩家进入");
            return;
        }
        if (!isStart) {
            JOptionPane.showMessageDialog(this, "请等待对方做决定");
            return;
        }
        //游戏结束时，不是你的回合，不再能下
        if (gameOver || !isYour) {
            return;
        }

        //将鼠标点击的坐标位置转换成网格索引
        xIndex = (e.getX() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;
        yIndex = (e.getY() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;

        //落在棋盘外不能下
        if (xIndex < 0 || xIndex > ROWS || yIndex < 0 || yIndex > COLS) {
            return;
        }
        //如果x，y位置已经有棋子存在，不能下
        if (!isFull(xIndex, yIndex)) {
            return;
        }
        addChess(xIndex, yIndex);
        if(isPlayWithAi && !isYour){
            addChess(1,i ++);
        }

    }

    //定义一个方法，判断落点是否有棋子
    public boolean isFull(int x, int y) {
        return board[y][x].equals(chessBoard);
    }

    //重新开始
    public void restart() {
        if (owner != null && rival != null) {
            owner.setGoBackCount(3);
            rival.setGoBackCount(3);
        }

        //清除棋子
        Arrays.fill(chessList, null);
        //恢复游戏相关的变量值
        isYour = owner.getBlack();
        gameOver = false; //游戏是否结束
        chessCount = 0; //当前棋盘棋子个数
        count = 0;
        newBoard();
        showBoard();
        repaint();
    }

    //悔棋
    public void goBack() {
        if (!isYour) {
            owner.setGoBackCount(owner.getGoBackCount() - 1);
            String msg = "您还剩" + owner.getGoBackCount() + "次悔棋机会";
            JOptionPane.showMessageDialog(this, msg);

        }

        chessList[chessCount - 1] = null;
        chessCount--;
        board[yIndex][xIndex] = chessBoard;
        if (chessCount > 0) {
            xIndex = chessList[chessCount - 1].getX();
            yIndex = chessList[chessCount - 1].getY();
        }

        showBoard();
        repaint();

        isYour = !isYour;
    }

    //判断是否可以悔棋
    public boolean canGoBack() {
        if (isYour) {
            String msg = "您现在还不能悔棋";
            JOptionPane.showMessageDialog(this, msg);
            return false;
        }

        if (gameOver) {
            String msg = "游戏已经结束！";
            JOptionPane.showMessageDialog(this, msg);
            return false;
        }

        if (chessCount == 0) {
            String msg = "还未下棋,不可悔棋";
            JOptionPane.showMessageDialog(this, msg);
            return false;
        }

        if (owner.getGoBackCount() == 0 || rival.getGoBackCount() == 0) {
            String msg = "您的悔棋机会已经用完";
            JOptionPane.showMessageDialog(this, msg);
            return false;
        }
        return true;
    }

    //投降
    public void surrender(String username) {
        boolean who = username.equals(owner.getUsername());
        String msg = (who ? owner.getPlayer() : rival.getPlayer()) + "投降," + (!who ? owner.getPlayer() : rival.getPlayer()) + "赢了";
        JOptionPane.showMessageDialog(this, msg);
        gameOver = true;
    }

    //定义一个方法，用于初始化棋盘
    public void newBoard() {
        board = new String[ROWS + 1][COLS + 1];
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board.length; j++) {
                board[i][j] = chessBoard;
            }
        }
    }

    //定义一个方法，用于输出棋盘
    public void showBoard() {
        System.out.println("棋盘更新，下棋人为：" + (isYour ? owner.getPlayer() : rival.getPlayer()));
        for (String[] strings : board) {
            for (int j = 0; j < board.length; j++) {
                System.out.print(" " + strings[j] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }

    //定义一个方法，用于输入棋子
    public void addChess(int x, int y) {
        if (gameOver) {
            return;
        }

        Chess chess = null;
        if (isYour) {
            if(!isPlayWithAi){
                HashMap<String, String> map = new HashMap<>();
                map.put("x",x + "");
                map.put("y",y + "");
                map.put("fromUser",owner.getUsername());
                Client.request("down", map, false);
            }
            board[y][x] = owner.getChess();
            chess = new Chess(x, y, owner.getChess().equals("X") ? Color.black : Color.WHITE);
        } else {
            board[y][x] = rival.getChess();
            chess = new Chess(x, y, rival.getChess().equals("X") ? Color.black : Color.WHITE);
        }

        chessList[chessCount++] = chess;
        showBoard();
        repaint();

        if (isWin(isYour ? owner : rival, x, y)) {
            showBoard();
            //返回获胜情况
//            HashMap<String, String> result = new HashMap<>();
//            result.put("win",isYour ? owner.getUsername() : rival.getUsername());
//            result.put("lost",isYour ? rival.getUsername() : owner.getUsername());
//            Client.request("update",result,false);

            String msg = String.format("恭喜，%s赢了！", isYour ? owner.getPlayer() : rival.getPlayer());
            JOptionPane.showMessageDialog(this, msg);
            gameOver = true;
        }

        isYour = !isYour;
    }

    //判断输赢
    public boolean isWin(Player player, int y, int x) {
        //判度左右两个方位
        int leftCount = 0, rightCount = 0;
        //向左判断
        for (int i = 1; y - i >= 0; i++) {
            if (board[x][y - i].equals(player.getChess())) {
                leftCount++;
            } else {
                break;
            }

        }
        //向右判断
        for (int i = 1; y + i <= 15; i++) {
            if (board[x][y + i].equals(player.getChess())) {
                rightCount++;
            } else {
                break;
            }
        }
        if (leftCount + rightCount == 4) {
            return true;
        }

        //判断上下两个方位
        int upCount = 0, underCount = 0;
        //向上判断
        for (int i = 1; x - i >= 0; i++) {
            if (board[x - i][y].equals(player.getChess())) {
                upCount++;
            } else {
                break;
            }
        }
        //向下判断
        for (int i = 1; x + i <= 15; i++) {
            if (board[x + i][y].equals(player.getChess())) {
                underCount++;
            } else {
                break;
            }
        }
        if (upCount + underCount == 4) {
            return true;
        }

        //判断右上和左下两个方向
        int rightUpCount = 0, leftDownCount = 0;
        //向右上判断
        for (int i = 1; x - i >= 0 && y + i <= 15; i++) {
            if (board[x - i][y + i].equals(player.getChess())) {
                rightUpCount++;
            } else {
                break;
            }
        }
        //向左下判断
        for (int i = 1; x + i <= 15 && y - i >= 0; i++) {
            if (board[x + i][y - i].equals(player.getChess())) {
                leftDownCount++;
            } else {
                break;
            }
        }
        if (rightUpCount + leftDownCount == 4) {
            return true;
        }

        //判断左上和右下两个方向
        int leftUpCount = 0, rightDownCount = 0;
        //向左上判断
        for (int i = 1; x - i >= 0 && y - i >= 0; i++) {
            if (board[x - i][y - i].equals(player.getChess())) {
                leftUpCount++;
            } else {
                break;
            }
        }
        //向右下判断
        for (int i = 1; x + i <= 15 && y + i <= 15; i++) {
            if (board[x + i][y + i].equals(player.getChess())) {
                rightDownCount++;
            } else {
                break;
            }
        }
        if (leftUpCount + rightDownCount == 4) {
            return true;
        }
        return false;
    }

    public Dimension getPreferredSize() {
        return new Dimension(MARGIN * 2 + GRID_SPAN * COLS, MARGIN * 2
                + GRID_SPAN * ROWS);
    }

    @Override
    public void mouseClicked(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}
